#include "components/TimeSequencePanel.h"

#include <set>
#include <string>
#include <unordered_map>

using models::Process;
using models::TimePoint;

struct DrawLine {
  std::string pid;
  int x1;
  int x2;
  int y;
  int line_type; // 1: solid, 2: dot
};

namespace components {
TimeSequencePanel::TimeSequencePanel(wxWindow *parent,
                                     const std::vector<Process> &processes,
                                     const std::vector<TimePoint> &time_points)
    : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
              wxBORDER_SIMPLE) {
  m_time_points = time_points;
  m_processes = processes;

  Bind(wxEVT_PAINT, &TimeSequencePanel::OnPaint, this);
}

void TimeSequencePanel::OnPaint(wxPaintEvent &event) {
  wxPaintDC dc(this);
  dc.Clear();

  int width, height;
  GetClientSize(&width, &height);

  // 设置绘图参数
  constexpr int margin = 100;
  constexpr int barHeight = 20;
  constexpr int barSpacing = 50;
  int x = margin;
  int y = margin;
  constexpr int CONST_X_TIMES = 5;

  // 绘制时间点竖线和标注
  std::set<int> time_points_queue;
  for (const auto &time : m_time_points) {
    time_points_queue.insert(time.t);
  }

  for (const auto &time : time_points_queue) {
    int xPos = x + time * CONST_X_TIMES;
    dc.DrawLine(xPos, margin, xPos, height - margin);
    dc.DrawText(wxString::Format("%d", time), xPos, margin - 20);
  }

  // 绘制每个进程的时序图
  std::unordered_map<std::string, DrawLine> draw_lines;
  for (const auto &process : m_processes) {
    draw_lines[process.pid + "c1"] = {process.pid, 0, 0, y, 0};
    draw_lines[process.pid + "io"] = {process.pid, 0, 0, y, 1};
    draw_lines[process.pid + "c2"] = {process.pid, 0, 0, y, 0};
    y += barHeight + barSpacing;
  }
  for (const auto &timepoint : m_time_points) {
    auto lines_name = timepoint.pid + timepoint.step;
    if (timepoint.action == "started") {
      draw_lines[lines_name].x1 = x + timepoint.t * CONST_X_TIMES;
    } else if (timepoint.action == "finished") {
      draw_lines[lines_name].x2 = x + timepoint.t * CONST_X_TIMES;
    }
  }

  // 绘制进程名
  y = margin;
  for (const auto &process : m_processes) {
    dc.DrawText(process.pid, margin - 40, y);
    y += barHeight + barSpacing;
  }

  // 绘制进程时序图
  for (const auto &drawline : draw_lines) {
    auto line = drawline.second;
    if (line.x1 != 0 && line.x2 != 0) {
      if (line.line_type == 0) {
        dc.SetPen(wxPen(*wxBLACK, 2, wxPENSTYLE_SOLID));
      } else {
        dc.SetPen(wxPen(*wxBLACK, 2, wxPENSTYLE_DOT));
      }
      dc.DrawLine(line.x1, line.y, line.x2, line.y);
    }
  }

  // 绘制图例
  // SOLID LINE is for computation
  dc.SetPen(wxPen(*wxBLACK, 2, wxPENSTYLE_SOLID));
  dc.DrawLine(5, 5, 50, 5);
  dc.DrawText("Computation", 60, 5);
  // DOTTED LINE is for I/O
  dc.SetPen(wxPen(*wxBLACK, 2, wxPENSTYLE_DOT));
  dc.DrawLine(5, 20, 50, 20);
  dc.DrawText("I/O", 60, 20);
}
} // namespace components